#include <iostream>
#include <string>
#include <vector>
#include <unistd.h>
#include <sys/wait.h>
#include "task.hpp"
// 创建类把管道管理起来,需要掌握父进程的写端和子进程的id
class Channel
{
public:
    Channel(int wfd, int SubProcessid, const std::string name)
        : _wfd(wfd), _SubProcessid(SubProcessid), _name(name)
    {
    }
    ~Channel()
    {
    }
    void CloseChannel() { close(_wfd); }
    void Wait()
    {
        pid_t rid = waitpid(_SubProcessid, nullptr, 0);
        if (rid > 0)
        {
            std::cout << "wait " << rid << " success" << std::endl;
        }
    }
    int GetWfd() { return _wfd; }
    int GetSubProcessid() { return _SubProcessid; }
    std::string GetName() { return _name; }

private:
    int _wfd;
    int _SubProcessid;
    std::string _name;
};


//& 输出/输入型
// const & 输入型
//* 输出型
//  task_t task: 回调函数
void CreatChannelAndSub(std::vector<Channel> *channels, int num,task_t task)
{
    for (int i = 0; i < num; i++)
    {
        // 创建管道
        int pipefd[2] = {0};
        int r = pipe(pipefd);
        if (r != 0)
            exit(1);
        // 创建子进程
        pid_t id = fork();
        if (id == 0)
        {
            // 子进程  :父写,子读,然后子干活
            close(pipefd[1]);
            dup2(pipefd[0],0);// 将管道的读端，重定向到标准输入
            task();
            close(pipefd[0]);
            exit(0);
        }
        close(pipefd[0]);
        // 创建Channel对象来管理管道和子进程
        std::string name = "channel-";
        name += std::to_string(i);
        // a. 子进程的pid b. 父进程关心的管道的w端
        channels->push_back(Channel(pipefd[1], id, name));
    }
}

void SendTaskCommand(int wfd, int command)
{
    write(wfd, &command, sizeof(int));
}

int NextChannel(int channelnum)
{
    static int next = 0;
    int channel = next;
    next++;
    next %= channelnum;
    return channel;
}

void CtrlChannelOnce(std::vector<Channel> &channels)
{
    sleep(1);
    // 挑选任务
    int taskcommand = SelectTask();
    // 挑选子进程
    int channel_index = NextChannel(channels.size());
    // 发送任务
    SendTaskCommand(channels[channel_index].GetWfd(), taskcommand);
    std::cout << std::endl;
    std::cout << "taskcommand: " << taskcommand << " channel: "
              << channels[channel_index].GetName() << " sub process: " << channels[channel_index].GetSubProcessid() << std::endl;
}

void CtrlChannel(std::vector<Channel> &channels, int time = -1)
{
    if (time < 0)
    {
        while (true)
            CtrlChannelOnce(channels);
    }
    else
    {
        while (time--)
            CtrlChannelOnce(channels);
    }
}

void CleanUpChannel(std::vector<Channel> &channels)
{
    for (auto &channel : channels)
    {
        channel.CloseChannel();
    }
    //注意
    for (auto &channel : channels)
    {
        channel.Wait();
    }
    // int i=channels.size()-1;
    // while(i)
    // {
    //     channels[i].CloseChannel();
    //     channels[i--].Wait();
    // }
}
//./processpool 5
int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        std::cerr << "Usage:" << argv[0] << "num" << std::endl;
        return 1;
    }
    LoadTask();
    int num = std::stoi(argv[1]);
    std::vector<Channel> channels;
    // 1.创建子进程和管道
    CreatChannelAndSub(&channels,num ,work);

    // 2.通过channels控制子进程
    CtrlChannel(channels, 5);

    // 3.回收channel //关闭所有的写端,等待子进程
    CleanUpChannel(channels);
    // ForTest(channels);

    return 0;
}

// void ForTest(std::vector<Channel> &channels)
// {
//     for (auto &channel : channels)
//     {
//         sleep(1);
//         std::cout << "Wfd" << channel.GetWfd() << std::endl;
//         std::cout << "Subprocessid:" << channel.GetSubProcessid() << std::endl;
//         std::cout << "Name:" << channel.GetName() << std::endl;
//         std::cout << "------------------------------------------------------" << std::endl;
//     }
// }